今天,我將介紹與 Output 裝飾器 (decorator) 相對應的 output 函數。 output 函數負責向父組件發送值。output 函數傳回一個 OutputEmitterRef,它有兩個方法:emit 和 subscribe。儘管 OutputEmitterRef 有 subscribe 方法來使用發出的值,但它與 RxJS 無關。與 @Output 裝飾器 (decorator) 相同, output 函數也有一個別名 (alias) 屬性,可以重新命名自訂事件。
在以下例子中,我展示了 output 如何向父組件傳送值,以及消費者如何使用 subscribe 方法使用傳送的值。
import { Component, ChangeDetectionStrategy, signal, output } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-photo-size-output',
standalone: true,
imports: [FormsModule],
template: `
<div style="margin-bottom: 1rem;">
Width: <input type="number" [(ngModel)]="width" />
Height: <input type="number" [(ngModel)]="height" />
<button (click)="size.emit({ width: width(), height: height() })">Change photo</button>
</div>
`,
})
export default class AppPhotoSizeOutputComponent {
width = signal(300);
height = signal(200);
size = output<{
width: number,
height: number,
}>({ alias: 'dimensions'});
}
AppPhotoSizeOutputComponent 的 width 和 height signals 綁定到 template-driven 表單。當使用者點擊按鈕時,點擊事件會將 width 和 height 物件傳送到 size output。 size output 的別名 dimensions;因此,自訂事件名稱被重新命名為 dimensions。
import { Component, ChangeDetectionStrategy, input } from '@angular/core';
@Component({
selector: 'app-photo-output',
standalone: true,
template: `
<div class="photo">
<img [src]="img()" alt="Random picture" />
</div>
`,
})
export default class AppPhotoOutputComponent {
img = input.required<string>();
}
AppPhotoOutputComponent 組件具有必需的 img signal input,用於將圖像 URL 綁定到圖像元素。
import { Component, ChangeDetectionStrategy, signal, output } from '@angular/core';
import AppPhotoOutputComponent from './photo-output.component';
import AppPhotoSizeOutputComponent from './photo-output-size-output.component';
@Component({
selector: 'app-photo-wrapper-output',
standalone: true,
imports: [AppPhotoSizeOutputComponent, AppPhotoOutputComponent],
template: `
<div class="photo-output-wrapper">
<app-photo-size-output (dimensions)="updateSize($event)" />
<app-photo-output [img]="img()" />
</div>
`,
})
export default class AppPhotoWrapperOutputComponent {
img = signal('https://picsum.photos/300/200');
imgUrl = output<string>();
updateSize(result: { width: number; height: number }) {
const { width, height } = result;
const url = `https://picsum.photos/${width}/${height}?random=${Date.now()}`;
this.img.set(url);
this.imgUrl.emit(url);
}
}
AppPhotoWrapperOutputComponent 組件是 AppPhotoSizeOutputComponent 和 AppPhotoOutputComponent 組件的容器。 AppPhotoSizeOutputComponent 組件的自訂 size 事件將值傳送到父組件。 updateSize 方法使用結果建構影像 URL,以 URL 覆寫 img signal,並將其傳送到 App 組件。 AppPhotoOutputComponent 所需的輸入綁定到 img signal 以顯示新圖片。
@Component({
selector: 'app-root',
standalone: true,
imports: [AppPhotoWrapperOutputComponent],
template: `
<p>{{ imgUrl() }}</p>
<app-photo-wrapper-output (imgUrl)="imgUrl.set($event)" />
`,
})
export class App {
imgUrl = signal('');
}
AppPhotoWrapperOutputComponent 組件將 imageUrl 傳送到 App 組件,並顯示該值。
subscribe 訂閱 output 值import { Component, signal, output } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-photo-size',
standalone: true,
imports: [FormsModule],
template: `
<div style="margin-bottom: 1rem;">
Width: <input type="number" [(ngModel)]="width" />
Height: <input type="number" [(ngModel)]="height" />
<button (click)="size.emit({ width: width(), height: height() })">Change photo</button>
</div>
`,
})
export default class AppPhotoSizeComponent {
width = signal(300);
height = signal(200);
size = output<{
width: number,
height: number,
}>();
}
AppPhotoSizeComponent 具有綁定到範本驅動表單 (template-driven form) 的 width 和 height signals。當使用者點擊按鈕時,點擊事件會將 width 和 height 物件傳送到 size output。
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
@Component({
selector: 'app-photo',
standalone: true,
template: `
<div class="photo">
<img [src]="img()" alt="Random picture" />
</div>
`,
})
export default class AppPhotoComponent {
img = signal('https://picsum.photos/300/200');
}
AppPhotoComponent 組件有一個 img signal,用於將圖像 URL 綁定到圖像元素。
import { Component, ChangeDetectionStrategy, contentChild, effect } from '@angular/core';
import AppPhotoComponent from './photo.component';
import AppPhotoSizeComponent from './photo-size.componen';
@Component({
selector: 'app-photo-wrapper',
standalone: true,
template: `
<div class="photo-wrapper">
<ng-content />
</div>
`,
})
export default class AppPhotoWrapperComponent {
photo = contentChild.required(AppPhotoComponent);
photoSize = contentChild.required(AppPhotoSizeComponent);
constructor() {
effect(() => {
this.photoSize().size.subscribe(({ width, height }) => {
const url = `https://picsum.photos/${width}/${height}?random=${Date.now()}`;
this.photo().img.set(url);
});
});
}
}
AppPhotoWrapperComponent 組件使用 contentChild 函數來查詢 AppPhotoComponent 和 AppPhotoSizeComponent 組件。 AppPhotoWrapperComponent 組件訂閱 AppPhotoSizeComponent 組件的 size output。當 size output 發出父級的值時, subscribe 方法會建構圖片 URL 並設定 AppPhotoComponent 組件的 img signal。signal 接收新值,AppPhotoComponent 組件顯示新圖片。
<h3>Subscribe output function</h3>
<app-photo-wrapper>
<app-photo-size />
<app-photo style="margin-bottom: 1rem;" />
</app-photo-wrapper>
在 App 組件中,AppPhotoSizeComponent 和 AppPhotoComponent 組件被投影到 AppPhotoWrapperComponent,以便 contentChild 函數可以查詢它們,並且可以透過 subscribe 訂閱 the size output。
output 函數允許元件向父組件發出值。output 函數傳回具有 emit 和 subscribe 方法的 OutputEmitterRef。 emit 方法將值傳送給父元件。 subscribe 方法以程式設計方式使用發出的值。output 函數接受帶有別名屬性的選項物件。內部 output 名稱可以與組件層級的事件名稱不同。outputToObservable 將輸出轉換為 Observable。 outputFromObservable 從 Observable 轉換為輸出。 這些功能可以在 rxjs-interop 套件中找到。鐵人賽的第 23 天到此結束。